#include "hook_lib.h"
#include <stdio.h>
#include <io.h>
#include <windows.h>
#include <assert.h>
#include <fcntl.h>
#include <process.h>

#define NO_STDERR
#define BUF_PIPE_SIZE 0x4000

static struct
{
    int fdpipe[2];/*read+write*/
    int old_fd;
    uintptr_t thr;
    char initialized;
}pipes[3];
static FILE* streams[3];
static void io_do(void* param)
{

   char buf[BUF_PIPE_SIZE];int r;
   switch ((int)param)
   {
       case 2:
#ifdef NO_STDERR
           break;
#endif
       case 1:
           while (( r = read(pipes[(int)param].fdpipe[0],buf,sizeof(buf))))
               assert(write(pipes[(int)param].old_fd,buf,r)==r);
           break;
       case 0:
           while (( r = read(pipes[(int)param].old_fd,buf,sizeof(buf))))
               assert(write(pipes[(int)param].fdpipe[1],buf,r)==r); 
           break;
       
       default:break;
   }
  
   _endthread();
   return;
}


static void init_stream(int num)
{
    
    assert(num<3 && num>=0);
    if (pipes[num].initialized) return;pipes[num].initialized=1;    
    assert(setvbuf(streams[num],NULL,_IONBF,0)==0);    
    assert(_pipe( pipes[num].fdpipe, sizeof(char[BUF_PIPE_SIZE]), O_BINARY )==0);
    assert(( pipes[num].old_fd=_dup(_fileno(streams[num])))!=-1);
    assert(_dup2(pipes[num].fdpipe[(num==0)?0:1], _fileno(streams[num]))==0);
    pipes[num].thr=_beginthread(io_do,0,(void*)num);
}

void hook_init(int argc, char** argv)
{
    streams[0]=stdin;
    streams[1]=stdout;
    streams[2]=stderr;
#ifdef NO_STDERR
 printf("Warning: stderr is disabled\n");
#endif

 
 init_stream(0); /*stdin*/
 init_stream(1); /*stdout*/
 init_stream(2); /*stderr*/
  
}
